package com.gome.boot.config.datasource.multiple;

import com.gome.boot.config.datasource.GomeBootVfs;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;

/**
 * 多数据源Mybatis基础配置.
 * <br/>具体应用继承此类实现数据源和Mybatis配置加载.
 *
 * @author baoxiufeng
 */
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
public abstract class BaseMybatisConfig extends MultipleDataSourceConfig {

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        VFS.addImplClass(GomeBootVfs.class);
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(multipleDataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage(getTypeAliasesPackage());
        sqlSessionFactoryBean.setPlugins(getPlugins());
        if (mapperLocations() != null) {
            sqlSessionFactoryBean.setMapperLocations(getMapperLocations(mapperLocations()));
        } else {
            sqlSessionFactoryBean.setMapperLocations(getMapperLocations());
        }
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
        sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
        sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
        sqlSessionFactory.getConfiguration().setLogImpl(Slf4jImpl.class);
        return sqlSessionFactory;
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSession() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

    /**
     * 获取实体对象所在包路径.
     * <br/>需要具体的应用去实现此方法.
     *
     * @return 实体对象所在包路径
     */
    protected String getTypeAliasesPackage() {
        return null;
    }

    /**
     * 获取自定义的拦截插件.
     *
     * @return 拦截插件
     */
    protected Interceptor[] getPlugins() {
        return null;
    }

    /**
     * 获取Mybatis的映射文件资源列表.
     * <br/>需要具体的应用去实现此方法.
     *
     * @return Mybatis的映射文件资源列表
     */
    protected Resource[] getMapperLocations() {
        return new Resource[0];
    }

    /**
     * 获取Mybatis的映射文件资源列表，支持正则匹配.
     * <br/>需要具体的应用去实现此方法.
     *
     * @return Mybatis的映射文件资源列表
     */
    protected String mapperLocations() {
        return null;
    }

    /**
     * 获取Mybatis的映射文件资源列表.
     *
     * @param mapperLocations Mybatis的映射文件列表
     * @return Mybatis的映射文件资源列表
     */
    private Resource[] getMapperLocations(String mapperLocations) {
        try {
            return new PathMatchingResourcePatternResolver().getResources(mapperLocations);
        } catch (IOException e) {
            return new Resource[0];
        }
    }
}
